package cn.lysoy.demo.dynamicDatasourceTest;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

/**
 * 简易动态数据库连接池
 * @author 宋杨
 * @email s2295938761@163.com
 * @phone 15216839375
 * @date 2022/9/1
 */
public class MyDynamicConnectionPool {
    HashMap<String, MyConnectionPool> pools = new HashMap<>();

    //提供静态的私有的本类对象
    private static MyDynamicConnectionPool myDynamicConnectionPool;
    //构造方法私有化
    private MyDynamicConnectionPool(List<DynamicPoolProperties> dynamicPoolPropertiesList) {
        init(dynamicPoolPropertiesList);
    }
    //提供静态的可以获取本类对象的方法。
    public synchronized static MyDynamicConnectionPool getPool(List<DynamicPoolProperties> dynamicPoolPropertiesList) {
        if(myDynamicConnectionPool ==null)
            myDynamicConnectionPool = new MyDynamicConnectionPool(dynamicPoolPropertiesList);
        return myDynamicConnectionPool;
    };

    //成员属性初始化
    private void init(List<DynamicPoolProperties> dynamicPoolPropertiesList) {
        for (DynamicPoolProperties dynamicPoolProperties : dynamicPoolPropertiesList) {
            MyConnectionPool myConnectionPool = new MyConnectionPool(dynamicPoolProperties.getProperties());
            pools.put(dynamicPoolProperties.getName(), myConnectionPool);
        }
    }

    /**
     * 从池中获取一个可用的连接
     * @return
     */
    public Connection getConn(String key) {
        return pools.containsKey(key) ? pools.get(key).getCon() : null;
    }

    private static class MyConnectionPool {


        MyConnectionPool(Properties properties) {
            setProperty(properties);
            init();
        }

        //成员属性
        //数据库连接属性
        private String driverClass;
        private String userName;
        private String url;
        private String password;
        //初始连接数量
        private int initCount = 5;
        //最小连接数量
        private int minCount = 5;
        //最大连接数量
        private int maxCount = 15;
        //当前的连接数量
        private int count;
        //使用集合存储连接
        LinkedList<Connection> conns = new LinkedList<Connection>();

        //成员属性初始化
        public void setProperty(Properties properties) {
            driverClass = properties.getProperty("jdbc.driverclass");
            url  = properties.getProperty("jdbc.url");
            userName = properties.getProperty("jdbc.username");
            password = properties.getProperty("jdbc.password");
            try {
                initCount = new Integer(properties.getProperty("jdbc.initCount"));
            } catch (NumberFormatException e) {
                System.out.println("initCount使用默认值："+initCount);
            }
            try {
                minCount = new Integer(properties.getProperty("jdbc.minCount"));
            } catch (NumberFormatException e) {
                System.out.println("minCount使用默认值："+minCount);
            }
            try {
                maxCount = new Integer(properties.getProperty("jdbc.maxCount"));
            } catch (NumberFormatException e) {
                System.out.println("maxCount使用默认值："+maxCount);
            }
        }

        /**
         * 初始化连接池
         */
        private void init() {
            // 循环的给集合中添加初始化个数个链接
            for (int i = 0; i < initCount; i++) {
                boolean flag = conns.add(createCon());
                if(flag) {
                    //添加成功之后就将给连接数量+1
                    count ++;
                }
            }
            System.out.println("连接池初始化完成");
        }
        /**
         * 创建一个可用的数据库连接
         * @return
         */
        private Connection createCon() {
            try {
                Class.forName(driverClass);
                return DriverManager.getConnection(url, userName, password);
            } catch (Exception e) {
                throw new RuntimeException("链接创建失败："+e.getMessage());
            }
        }

        /**
         * 池中连接自动增长
         */
        private synchronized void addAuto() {
            // 增长步长为2
            if (count == maxCount) {
                throw new RuntimeException("池中数量已经达到最大，不能再增长");
            }
            // 增长过程中，判断池中的个数
            for (int i = 0; i < 2; i++) {
                if (count == maxCount) {
                    break;//如果已经到最大值，则直接结束循环
                }
                conns.add(createCon());
                count++;
            }
        }

        /**
         * 从池中获取一个可用的连接
         * @return
         */
        public Connection getCon() {
            //判断池中是否有空闲链接
            if(conns.size()>0) {
                //如果有就直接返回
                return conns.removeFirst();
            }
            //如果池中没有空闲的连接
            //判断总连接数是否已经达到上限
            if(count < maxCount) {
                //让连接池自动增长
                addAuto();
                //自动增长完成之后，递归调用返回连接的方法
                return getCon();
            }
            //如果池中的连接数已经达到上限，就等一会再获取
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return  getCon();
        }

        /**
         * 连接池自动缩减的方法
         */
        private synchronized void reduce() {
            //当连接数量大于最小连接数量，并且池中有空闲连接
            if(count > minCount && conns.size() > 0) {
                try {
                    //从池中获取一个链接，并且关闭
                    Connection con = conns.removeFirst();
                    con.close();
                    con = null;
                    //如果关闭了一个连接，就将当前的链接数量-1
                    count--;
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 还回连接到池中
         * @param con
         */
        public void returnCon(Connection con) {
            //将连接直接放入集合
            conns.add(con);
            //连接还回之后，马上缩减连接池
            reduce();
        }
    }
}
